/**
 * create by zhike
 * date:2015年3月2日
 */
package com.acooly.module.openapi.client.provider.shengpay;

import com.acooly.core.utils.BeanUtils;
import com.acooly.core.utils.FreeMarkers;
import com.acooly.core.utils.mapper.BeanCopier;
import com.acooly.core.utils.net.HttpResult;
import com.acooly.module.openapi.client.api.AbstractApiServiceClient;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.api.exception.ApiClientSocketTimeoutException;
import com.acooly.module.openapi.client.api.exception.ApiServerException;
import com.acooly.module.openapi.client.api.marshal.ApiMarshal;
import com.acooly.module.openapi.client.api.marshal.ApiUnmarshal;
import com.acooly.module.openapi.client.api.message.PostRedirect;
import com.acooly.module.openapi.client.api.transport.Transport;
import com.acooly.module.openapi.client.provider.shengpay.domain.ShengpayNotify;
import com.acooly.module.openapi.client.provider.shengpay.domain.ShengpayRequest;
import com.acooly.module.openapi.client.provider.shengpay.domain.ShengpayResponse;
import com.acooly.module.openapi.client.provider.shengpay.exception.ShengpayProcessingException;
import com.acooly.module.openapi.client.provider.shengpay.marshall.ShengpayNotifyUnmarshall;
import com.acooly.module.openapi.client.provider.shengpay.marshall.ShengpayRedirectPostMarshall;
import com.acooly.module.openapi.client.provider.shengpay.marshall.ShengpayRequestMarshall;
import com.acooly.module.openapi.client.provider.shengpay.marshall.ShengpayResponseUnmarshall;
import com.acooly.module.openapi.client.provider.shengpay.message.ShengpaySingleOrderQueryRequest;
import com.acooly.module.openapi.client.provider.shengpay.message.ShengpaySingleOrderQueryResponse;
import com.acooly.module.openapi.client.provider.shengpay.utils.HttpServletRequestUtil;
import com.acooly.module.openapi.client.provider.shengpay.utils.SignUtils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.sdo.mas.common.api.common.entity.Header;
import com.sdo.mas.common.api.common.entity.Sender;
import com.sdo.mas.common.api.common.entity.Service;
import com.sdo.mas.common.api.common.entity.Signature;
import com.sdo.mas.common.api.query.order.entity.syn.single.OrderQueryRequest;
import com.sdo.mas.common.api.query.order.entity.syn.single.OrderQueryResponse;
import com.sdo.mas.common.api.query.order.service.QueryOrderAPI;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.print.attribute.standard.Copies;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 上海银行P2P存管ApiService执行器  外部业务禁止使用
 *
 * @author zhike
 */
@Slf4j
@Component("shengpayApiServiceClient")
public class ShengpayApiServiceClient
        extends AbstractApiServiceClient<ShengpayRequest, ShengpayResponse, ShengpayNotify, ShengpayNotify> {


    @Resource(name = "shengpayHttpTransport")
    private Transport transport;
    @Resource(name = "shengpayRequestMarshall")
    private ShengpayRequestMarshall requestMarshal;
    @Resource(name = "shengpayResponseUnmarshall")
    private ShengpayResponseUnmarshall responseUnmarshal;
    @Resource(name = "shengpayNotifyUnmarshall")
    private ShengpayNotifyUnmarshall notifyUnmarshal;
    @Resource(name = "shengpayRedirectPostMarshall")
    private ShengpayRedirectPostMarshall shengpayRedirectPostMarshall;

    @Autowired
    private OpenAPIClientShengpayProperties openAPIClientYipayProperties;

    /**
     * 同步请求
     *
     * @param request
     * @return
     */
    @Override
    public ShengpayResponse execute(ShengpayRequest request) {
        try {
            beforeExecute(request);
            String serviceName = ShengpayConstants.getServiceName(request);
            String url = ShengpayConstants.getCanonicalUrl(openAPIClientYipayProperties.getGatewayUrl(), serviceName);
            request.setService(serviceName);
            Map<String,String> requestMessage = requestMarshal.marshal(request);
            log.info("请求报文：{}",requestMessage);
            Map<String, String> headers = Maps.newHashMap();
            headers.put(ShengpayConstants.SIGN_TYPE_KEY,requestMessage.get(ShengpayConstants.SIGN_TYPE_KEY));
            headers.put(ShengpayConstants.SIGN_MSG_KEY,requestMessage.get(ShengpayConstants.SIGN_MSG_KEY));
            String requestBodyMessage = requestMessage.get(ShengpayConstants.REQUEST_BODY_KEY);
            HttpResult result = getTransport().request(requestBodyMessage, url,headers);
            if (result.getStatus() >= HttpStatus.SC_BAD_REQUEST) {
                throw new RuntimeException("HttpStatus:" + result.getStatus());
            }
            Map<String,String> respMap = Maps.newHashMap();
            respMap.put(ShengpayConstants.SIGN_MSG_KEY,result.getHeaders().get(ShengpayConstants.SIGN_MSG_KEY));
            respMap.put(ShengpayConstants.RESPONSE_BODY_KEY,result.getBody());
            ShengpayResponse t = this.responseUnmarshal.unmarshal(respMap, serviceName);
            afterExecute(t);
            return t;
        } catch (ShengpayProcessingException pe) {
            log.error("解析响应报文异常：" + pe.getMessage(), pe);
            throw pe;
        } catch (ApiClientSocketTimeoutException ase) {
            log.error("响应超时异常：" + ase.getMessage(), ase);
            throw new ShengpayProcessingException(ase.getMessage());
        } catch (ApiServerException ose) {
            log.error("服务器:" + ose.getMessage(), ose);
            throw ose;
        } catch (ApiClientException oce) {
            log.error("客户端:" + oce.getMessage(), oce);
            throw oce;
        } catch (Exception e) {
            log.error("内部错误:" + e.getMessage(), e);
            throw new ApiClientException("内部错误:" + e.getMessage());
        }
    }

    /**
     * 单笔订单查询接口（webService请求）
     * @param request
     * @return
     */
    public ShengpaySingleOrderQueryResponse executeQuery(ShengpaySingleOrderQueryRequest request) {
        ShengpaySingleOrderQueryResponse response = new ShengpaySingleOrderQueryResponse();
        try {
            String waitSignStr = request.getSignStr()+openAPIClientYipayProperties.getMd5Key();
            log.info("代签字符串：{}",waitSignStr);
            //加密sign
            byte[] enbyte = SignUtils.getByte(waitSignStr);
            String sign = SignUtils.bin2hex(enbyte);
            //填充盛付通接口需要的参数
            OrderQueryRequest shengpayQueryRequest = new OrderQueryRequest();
            Signature signature = new Signature();
            signature.setSignType("MD5");
            signature.setSignMsg(sign);
            Header header = new Header();
            header.setCharset(ShengpayConstants.SHENGPAY_CHARSET);
            header.setSendTime(request.getSendTime());
            header.setTraceNo(request.getTransNo());
            Sender sender = new Sender();
            sender.setSenderId(openAPIClientYipayProperties.getMerchantNo());
            header.setSender(sender);
            Service service = new Service();
            service.setServiceCode("QUERY_ORDER_REQUEST");
            service.setVersion("V4.3.1.1.1");
            header.setService(service);
            shengpayQueryRequest.setMerchantNo(openAPIClientYipayProperties.getMerchantNo());
            shengpayQueryRequest.setOrderNo(request.getOrderNo());
            shengpayQueryRequest.setTransNo(request.getTransNo());
            shengpayQueryRequest.setSignature(signature);
            shengpayQueryRequest.setHeader(header);
            JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
            factory.setServiceClass(QueryOrderAPI.class);
            factory.setAddress(openAPIClientYipayProperties.getQueryGatewayUrl());
            QueryOrderAPI queryOrderAPI = (QueryOrderAPI) factory.create();
            log.info("请求报文：{}",JSON.toJSONString(shengpayQueryRequest));
            OrderQueryResponse orderQueryResponse = queryOrderAPI.queryOrder(shengpayQueryRequest);
            BeanCopier.copy(orderQueryResponse,response);
            if(orderQueryResponse.getReturnInfo() != null) {
                response.setErrorCode(orderQueryResponse.getReturnInfo().getErrorCode());
                response.setErrorMsg(orderQueryResponse.getReturnInfo().getErrorMsg());
            }
            response.setServiceCode(request.getServiceCode());
            response.setVersion(request.getVersion());
            log.info("响应报文：{}",JSON.toJSONString(orderQueryResponse));
        }catch (Exception e) {
            log.error("内部错误:" + e.getMessage(), e);
            throw new ApiClientException("内部错误:" + e.getMessage());
        }
        return response;
    }

    private HttpPost buildHttpPost(String url, String body, ContentType contentType) {
        HttpPost post = new HttpPost(url);
        post.setEntity(new StringEntity(body, contentType));
        return post;
    }

    private ContentType loadContentType(ContentType contentType) {
        if (contentType != null) {
            return contentType;
        }
        return ContentType.create(
                ContentType.APPLICATION_FORM_URLENCODED.getMimeType(), "utf-8");
    }


    @Override
    public String redirectGet(ShengpayRequest request) {
        PostRedirect postRedirect = redirectPost(request);
        Map<String, Object> templateData = Maps.newHashMap();
        templateData.put("random", RandomStringUtils.randomAlphanumeric(10));
        templateData.put("redirectUrl", postRedirect.getRedirectUrl());
        templateData.put("formDatas", postRedirect.getFormDatas());
        String template =
                "<form accept-charset=\"utf-8\" id=\"redirectForm_${random}\" action=\"${redirectUrl}\" method=\"post\">  \n" +
                        "<#list formDatas?keys as key>\n" +
                        "    <input name=\"${key}\" value='${formDatas[key]?default(\"\")}' type='hidden'/>\n" +
                        "</#list>\n" +
                        "</form>\n" +
                        "<script>document.getElementById(\"redirectForm_${random}\").submit();</script>";
        String fromHtml = FreeMarkers.rendereString(template, templateData);
        return fromHtml;
    }

    @Override
    public PostRedirect redirectPost(ShengpayRequest request) {
        try {
            // 跳转类接口，设置通知地址
            return shengpayRedirectPostMarshall.marshal(request);
        } catch (ApiServerException ose) {
            log.warn("服务器错误:" + ose.getMessage(), ose);
            throw ose;
        } catch (ApiClientException oce) {
            log.warn("客户端异常:" + oce.getMessage(), oce);
            throw oce;
        } catch (Exception e) {
            log.warn("内部错误:" + e.getMessage(), e);
            throw new ApiClientException("内部错误:" + e.getMessage());
        }
    }

    public ShengpayNotify notice(HttpServletRequest request, String serviceKey) {
        try {
            Map<String, String> notifyData = HttpServletRequestUtil.getNoticeDateMap(request);
            ShengpayNotify notify = getNoticeUnmarshal().unmarshal(notifyData, serviceKey);
            afterNotice(notify);
            log.info("通知报文：{}", JSON.toJSONString(notify));
            return notify;
        } catch (ApiClientException oce) {
            log.warn("客户端:{}", oce.getMessage());
            throw oce;
        } catch (Exception e) {
            log.warn("内部错误:{}", e.getMessage());
            throw new ApiClientException("内部错误:" + e.getMessage());
        }
    }

    @Override
    protected String getRedirectGateway() {
        return openAPIClientYipayProperties.getGatewayUrl();
    }

    @Override
    protected ApiMarshal<String, ShengpayRequest> getRequestMarshal() {
        return null;
    }


    @Override
    protected ApiMarshal<String, ShengpayRequest> getRedirectMarshal() {
        return null;
    }

    @Override
    protected ApiUnmarshal<ShengpayNotify, Map<String, String>> getNoticeUnmarshal() {
        return this.notifyUnmarshal;
    }


    protected ApiUnmarshal<ShengpayResponse, String> getResponseUnmarshalSpec() {
        return null;
    }

    @Override
    protected ApiUnmarshal<ShengpayResponse, String> getResponseUnmarshal() {
        return null;
    }

    @Override
    protected ApiUnmarshal<ShengpayNotify, Map<String, String>> getReturnUnmarshal() {
        return this.notifyUnmarshal;
    }

    @Override
    protected Transport getTransport() {
        return this.transport;
    }

    @Override
    public String getName() {
        return ShengpayConstants.PROVIDER_NAME;
    }


}
